﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
using SmartParking.Data;
using SmartParking.Data.Entities;

namespace SmartParking.Bussiness
{
    public class LogManager
    {
        /// <summary>
        /// Add new log entry
        /// </summary>
        public static void Log(int managerID, LogActions action, string ipAddress, string affectedTable = "", string affectedID = "", string message = "")
        {
            using (var context = new SmartParkingContext())
            {
                context.Logs.Add(
                    new Log
                        {
                            ManagerID = managerID,
                            Action = action.ToString(),
                            AffectedTable = affectedTable,
                            AffectedID = affectedID,
                            Message = message,
                            IPAddress = ipAddress == "::1" ? "127.0.0.1" : ipAddress,
                            Date = DateTime.UtcNow
                        }
                    );
                context.SaveChanges();
            }
        }

        /// <summary>
        /// Add new info log entry
        /// </summary>
        public static void Info(int managerID, string ipAddress, string message)
        {
            Log(managerID, LogActions.INFO, ipAddress, message: message);
        }

        /// <summary>
        /// Add new warning log entry
        /// </summary>
        public static void Warning(int managerID, string ipAddress, string message)
        {
            Log(managerID, LogActions.WARNING, ipAddress, message: message);
        }

        /// <summary>
        /// Add new error log entry
        /// </summary>
        public static void Error(int managerID, string ipAddress, string message, string stackTrace = "")
        {
            Log(managerID, LogActions.ERROR, ipAddress, message: message + " " + stackTrace);
        }

        /// <summary>
        /// Add new fatal error log entry
        /// </summary>
        public static void FatalError(int managerID, string ipAddress, string message)
        {
            Log(managerID, LogActions.FATALERROR, ipAddress, message: message);
        }

        /// <summary>
        /// Add debug log entry
        /// </summary>
        public static void Debug(int managerID, string ipAddress, string message)
        {
            try
            {
                if (SmartParkingSettings.Logger)
                {
                    Log(managerID, LogActions.DEBUG, ipAddress, message: message);
                }
            }
            catch
            {
            }         
        }

        /// <summary>
        /// Return all log entries
        /// </summary>
        /// <returns></returns>
        public static List<Log> GetLog(Func<Log, bool> conditions = null)
        {
            using (var context = new SmartParkingContext())
            {
                return conditions == null ? context.Logs.ToList() : context.Logs.Where(conditions).ToList();
            }
        }

        /// <summary>
        /// Bind all log entries into a grid view
        /// </summary>
        /// <param name="grid"></param>
        public static void BindLog(ref GridView grid, int managerID = -1, string affectedTable = "", string action = "", string ipAddress = "", Nullable<DateTime> fromDate = null, Nullable<DateTime> toDate = null)
        {
            var conditions = new Func<Log, bool>(item => managerID != -1 && item.ManagerID == managerID);
            if (!String.IsNullOrEmpty(affectedTable)) conditions += item => item.AffectedTable == affectedTable;
            if (!String.IsNullOrEmpty(action)) conditions += item => item.Action == action;
            if (!String.IsNullOrEmpty(ipAddress)) conditions += item => item.IPAddress == ipAddress;
            if (fromDate != null) conditions += item => item.Date >= fromDate.Value;
            if (toDate != null) conditions += item => item.Date <= toDate.Value.AddDays(1);
            var log = GetLog(conditions);
            grid.DataSource = log;
            grid.DataBind();
        }

        /// <summary>
        /// Return all IP addresses in log entries
        /// </summary>
        /// <returns></returns>
        public static List<string> GetIPAddresses()
        {
            List<Log> logs = LogManager.GetLog();
            var result =
                (from log in logs
                 select log.IPAddress).Distinct();
            return result.ToList();
        }

        /// <summary>
        /// Bind all IP addresses in log entries into a drop down list
        /// </summary>
        /// <param name="list"></param>
        public static void BindIPAddresses(ref DropDownList list)
        {
            list.DataSource = LogManager.GetIPAddresses();
            list.DataBind();
        }

        /// <summary>
        /// Return all managers in log entries
        /// </summary>
        /// <returns></returns>
        public static List<Manager> GetManagers()
        {
            List<Log> logs = LogManager.GetLog();
            List<Manager> managers = SecurityManager.GetManagers();

            var result =
                (from log in logs
                 join manager in managers on log.ManagerID equals manager.ManagerID
                 select manager).Distinct();
            return result.ToList();
        }

        /// <summary>
        /// Bind all managers in log entries into a drop down list
        /// </summary>
        /// <param name="list"></param>
        public static void BindManagers(ref DropDownList list)
        {
            list.DataSource = LogManager.GetManagers();
            list.DataTextField = "UserName";
            list.DataValueField = "ManagerID";
            list.DataBind();
        }

        /// <summary>
        /// Return all tables in log entries
        /// </summary>
        /// <returns></returns>
        public static List<string> GetTables()
        {
            List<Log> logs = LogManager.GetLog();
            var result =
                (from log in logs
                 select log.AffectedTable).Distinct();
            return result.ToList();
        }

        /// <summary>
        /// Bind all tables in log entries into a drop down list
        /// </summary>
        /// <param name="list"></param>
        public static void BindTables(ref DropDownList list)
        {
            list.DataSource = LogManager.GetTables();
            list.DataBind();
        }
    }

    public enum LogActions
    {
        SELECT = 0,
        INSERT = 1,
        UPDATE = 2,
        DELETE = 3,
        INFO = 4,
        WARNING = 5,
        ERROR = 6,
        FATALERROR = 7,
        DEBUG = 8
    }
}